import {uuid} from "@/utils/zzDouUtils/uuid";

/**
 * 为一个对象填充一个对象
 * @param obj 目标对象 {}
 * @param element 添加的对象 {}
 * @param ignoreKeys 需要忽略的key数组
 * <p>
 *    Object.assign(target, ...sources)
 *    其中，target 是目标对象，sources 是一个或多个源对象。它会返回目标对象 target。
 *    Object.assign() 方法会遍历每个源对象的自有可枚举属性，并将它们复制到目标对象中。
 *    如果多个源对象具有相同的属性名，则后面的源对象的属性会覆盖前面的源对象的属性。如果目标对象中已经存在相同的属性名，则它会被覆盖。
 *    需要注意的是，Object.assign() 方法只会复制源对象的自有可枚举属性，而不会复制其原型链上的属性。
 *    另外，它也不会复制源对象的访问器属性（getter 和 setter）
 * </p>
 */
export function fillObj(obj, element, ...ignoreKeys) {
    const e1 = copyObj(element);
    for (let i = 0; i < ignoreKeys.length; i++) {
        delete e1[ignoreKeys[i]];
    }
    return Object.assign(obj, e1);
}

export function fillNode(obj, key, value) {
    let element = {};
    element[key] = value;
    Object.assign(obj, element);
}

/**
 * 拷贝成一个新对象
 * @param obj 对象
 */
export function copyObj(obj) {
    return {...obj}
}

/**
 * 判断一个对象是否为空
 * @param obj 对象
 * @return
 * null true
 * {} true
 * undefined true
 */
export function isEmpty(obj) {
    if (isNull(obj)){
        return true;
    }
    if (isObj(obj)){
        return toJsonStr(obj) === '{}' || keys(obj).length === 0;
    }else if (isStr(obj)){
        return isEmptyStr(obj)
    }
    return isNull(obj) || obj === '' || !isObj(obj) || toJsonStr(obj) === '{}' || keys(obj).length === 0;
}

export function isNotEmpty(obj) {
    return isEmpty(obj) === false;
}
/**
 * 判断参数是否是字符串
 * @param str 参数
 */
export function isStr(str) {
    return typeof(str) == "string" || str.constructor === String || Object.prototype.toString.call(str) === "[object String]";
}

/**
 * 判断一个对象是否为 null
 * @param obj 对象
 * @return
 * null true
 * undefined true
 * {} false
 */
export function isNullObj(obj) {
    return isNull(obj) && isObj(obj);
}

/**
 * 判断参数是否是对象
 * @param obj 对象
 * @return
 * null false
 * undefined false
 * '123' false
 * 123 false
 * {} true
 */
export function isObj(obj) {
    return typeof(obj) == "object" || obj.constructor === Object || Object.prototype.toString.call(obj) === '[object Object]';
}

export function isNotNull(obj) {
    return isNull(obj) === false;
}

export function isNull(obj) {
    return obj === undefined || typeof obj === 'undefined' || obj === null;
}

export function toJsonStr(obj) {
    return JSON.stringify(obj);
}

export function parseObj(str) {
    return JSON.parse(str);
}

export function keys(obj) {
    return Object.keys(obj);
}

export function isEmptyStr(str) {
    return isNull(str) || str === '' || /^\s*$/.test(str);
}

export function isNotEmptyStr(str) {
    return isEmptyStr(str) === false;
}

export function isnumber(number) {
    return /^(-?\d+)(\.\d+)?$/.test(number);
}

export function equals(var1, var2) {
    return var1 == var2;
}

export function notEquals(var1, var2) {
    return !equals(var1, var2);
}

const regex$ = /\${(.*?)}/g;
/**
 * 字符串格式化
 * @param str  'hello ${name},today is ${week}'
 * @param obj {name:'doudou',week:'Monday'}
 * @return 'hello doudou,today is Monday'
 */
export function strFormat(str, obj) {
    // 使用正则表达式匹配占位符，并替换为对象的属性值
    return str.replace(regex$, (match, p1) => isNull(obj[p1.trim()]) ? match : obj[p1.trim()]);
}

/**
 * 返回占位key
 * @param str  'hello ${name},today is ${week}'
 * @return {name:null,week:null}
 * 使用了正则表达式/\${(.*?)}/g来匹配${}之间的变量名。
 * 然后，使用matchAll()方法获取所有匹配的结果，并遍历每个匹配项，
 * 将变量名作为对象的属性，初始值设为null。最后返回这个对象。
 */
export function strExtract(str) {
    const variables = {};
    for (const match of str.matchAll(regex$)) {
        variables[match[1].trim()] = null;
    }
    return variables;
}

/**
 * 字符串替换
 * @param str 字符串 '*ello ^orld'
 * @param targets 匹配的参数集合  ['*','^']
 * @param changes 改变的参数集合  ['H','W'] 两个集合的数量必须一致，通过顺序对应
 * @return 'Hello World'
 */
export function strReplaceAll(str,targets,changes){
    if (targets.length !== changes.length){
        return str;
    }
    for (let i = 0; i < targets.length; i++) {
        str.replace(targets[i],changes[i]);
    }
    return str;
}

/**
 * 获取文件后缀
 */
export function getFileType(file) {
    return file.name.replace(/.+\./, "").toLowerCase();
}

/**
 * 返回一个临时文件的地址
 */
export function createFileUrl(file) {
    return URL.createObjectURL(file.raw);
}

/**
 * base64图片转file的方法（base64图片）
 */
export function base64ToFile(base64) {
    // 将base64按照 , 进行分割 将前缀  与后续内容分隔开
    const data = base64.split(',')
    // 利用正则表达式 从前缀中获取图片的类型信息（image/png、image/jpeg、image/webp等）
    const type = data[0].match(/:(.*?);/)[1]
    // 从图片的类型信息中 获取具体的文件格式后缀（png、jpeg、webp）
    const suffix = type.split('/')[1]
    // 使用atob()对base64数据进行解码  结果是一个文件数据流 以字符串的格式输出
    const bstr = window.atob(data[1])
    // 获取解码结果字符串的长度
    let n = bstr.length
    // 根据解码结果字符串的长度创建一个等长的整形数字数组
    // 但在创建时 所有元素初始值都为 0
    const u8arr = new Uint8Array(n)
    // 将整形数组的每个元素填充为解码结果字符串对应位置字符的UTF-16 编码单元
    while (n--) {
        // charCodeAt()：获取给定索引处字符对应的 UTF-16 代码单元
        u8arr[n] = bstr.charCodeAt(n)
    }
    // 利用构造函数创建File文件对象
    // new File(bits, name, options)
    const file = new File([u8arr], `${uuid(10)}.${suffix}`, {
        type: type
    })
    // 将File文件对象返回给方法的调用者
    return file
}
